package com.sdgakj.utils;

import java.util.Collection;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaBuilder.In;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import org.springside.modules.utils.Collections3;

import com.google.common.collect.Lists;

public class SchoolSpecifications {

    @SuppressWarnings({ "rawtypes", "unchecked", "incomplete-switch" })
    public static <T> Specification<T> bySearchFilter(final Collection<SchoolSearchFilter> filters,
            final Class<T> entityClazz) {
        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                if (Collections3.isNotEmpty(filters)) {

                    List<Predicate> predicates = Lists.newArrayList();
                    Predicate orPredicate = builder.disjunction();
                    for (SchoolSearchFilter filter : filters) {
                        // nested path translate, 如Task的名为"user.name"的filedName, 转换为Task.user.name属性
                        String[] names = StringUtils.split(filter.fieldName, ".");
                        Path expression = root.get(names[0]);
                        for (int i = 1; i < names.length; i++) {
                            expression = expression.get(names[i]);
                        }
                        switch (filter.operator) {
                            case EQ:
                                predicates.add(builder.equal(expression, filter.value));
                                break;
                            case NOTEQ:
                                predicates.add(builder.notEqual(expression, filter.value));
                                break;
                            case LIKE:
                                predicates.add(builder.like(expression, "%" + filter.value + "%"));
                                break;
                            case GT:
                                predicates.add(builder.greaterThan(expression, (Comparable) filter.value));
                                break;
                            case LT:
                                predicates.add(builder.lessThan(expression, (Comparable) filter.value));
                                break;
                            case GTE:
                                predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.value));
                                break;
                            case LTE:
                                predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.value));
                                break;
                            case BETWEEN:
                                predicates.add(builder.between(expression, (Comparable) filter.value,
                                        (Comparable) filter.value));
                                break;
                            case IN:
                                In<Long> in = builder.in(expression);
                                String[] strs = filter.value.toString().split(",");
                                for (String str : strs) {
                                    in.value(Long.valueOf(str));
                                }
                                predicates.add(in);
                                break;
                            // 加入OR
                            case OREQBEGIN:
                                orPredicate = builder.or(orPredicate,
                                        builder.or(builder.equal(expression, filter.value)));
                                break;
                            case ORLIKEBEGIN:
                                orPredicate = builder.or(orPredicate,
                                        builder.or(builder.like(expression, "%" + filter.value + "%")));
                                break;
                            case OREQ:
                                orPredicate = builder.or(orPredicate,
                                        builder.or(builder.equal(expression, filter.value)));
                                break;
                            case ORLIKE:
                                orPredicate = builder.or(orPredicate,
                                        builder.or(builder.like(expression, "%" + filter.value + "%")));
                                break;
                            case OREQEND:
                                orPredicate = builder.or(orPredicate,
                                        builder.or(builder.equal(expression, filter.value)));
                                predicates.add(orPredicate);
                                break;
                            case ORLIKEEND:
                                orPredicate = builder.or(orPredicate,
                                        builder.or(builder.like(expression, "%" + filter.value + "%")));
                                predicates.add(orPredicate);
                                break;
                        }
                    }
                    // 将所有条件用 and 联合起来
                    if (!predicates.isEmpty()) {
                        return builder.and(predicates.toArray(new Predicate[predicates.size()]));
                    }
                }
                return builder.conjunction();
            }
        };
    }

}
